{
GtkApplicationWindow *window = GTK_APPLICATION_WINDOW (group);
+ /* may be NULL after dispose has run */
+ if (!window->priv->actions)
+ return g_new0 (char *, 0 + 1);
+
return g_action_group_list_actions (G_ACTION_GROUP (window->priv->actions));
}
{
GtkApplicationWindow *window = GTK_APPLICATION_WINDOW (group);
+ if (!window->priv->actions)
+ return FALSE;
+
return g_action_group_query_action (G_ACTION_GROUP (window->priv->actions),
action_name, enabled, parameter_type, state_type, state_hint, state);
}
{
GtkApplicationWindow *window = GTK_APPLICATION_WINDOW (group);
- return g_action_group_activate_action (G_ACTION_GROUP (window->priv->actions), action_name, parameter);
+ if (!window->priv->actions)
+ return;
+
+ g_action_group_activate_action (G_ACTION_GROUP (window->priv->actions), action_name, parameter);
}
static void
{
GtkApplicationWindow *window = GTK_APPLICATION_WINDOW (group);
- return g_action_group_change_action_state (G_ACTION_GROUP (window->priv->actions), action_name, state);
+ if (!window->priv->actions)
+ return;
+
+ g_action_group_change_action_state (G_ACTION_GROUP (window->priv->actions), action_name, state);
}
static GAction *
{
GtkApplicationWindow *window = GTK_APPLICATION_WINDOW (action_map);
+ if (!window->priv->actions)
+ return NULL;
+
return g_action_map_lookup_action (G_ACTION_MAP (window->priv->actions), action_name);
}
{
GtkApplicationWindow *window = GTK_APPLICATION_WINDOW (action_map);
+ if (!window->priv->actions)
+ return;
+
g_action_map_add_action (G_ACTION_MAP (window->priv->actions), action);
}
{
GtkApplicationWindow *window = GTK_APPLICATION_WINDOW (action_map);
+ if (!window->priv->actions)
+ return;
+
g_action_map_remove_action (G_ACTION_MAP (window->priv->actions), action_name);
}
g_clear_object (&window->priv->app_menu_section);
g_clear_object (&window->priv->menubar_section);
- g_clear_object (&window->priv->actions);
G_OBJECT_CLASS (gtk_application_window_parent_class)
->dispose (object);
+
+ /* We do this below the chain-up above to give us a chance to be
+ * removed from the GtkApplication (which is done in the dispose
+ * handler of GtkWindow).
+ *
+ * That reduces our chances of being watched as a GActionGroup from a
+ * muxer constructed by GtkApplication. Even still, it's
+ * theoretically possible that someone else could be watching us.
+ * Therefore, we have to take care to ensure that we don't violate our
+ * obligations under the interface of GActionGroup.
+ *
+ * The easiest thing is just for us to act as if all of the actions
+ * suddenly disappeared.
+ */
+ if (window->priv->actions)
+ {
+ gchar **action_names;
+ guint signal;
+ gint i;
+
+ /* Only send the remove signals if someone is listening */
+ signal = g_signal_lookup ("action-removed", G_TYPE_ACTION_GROUP);
+ if (signal && g_signal_has_handler_pending (window, signal, 0, TRUE))
+ /* need to send a removed signal for each action */
+ action_names = g_action_group_list_actions (G_ACTION_GROUP (window->priv->actions));
+ else
+ /* don't need to send signals: nobody is watching */
+ action_names = NULL;
+
+ /* Free the group before sending the signals for two reasons:
+ *
+ * 1) we want any incoming calls to see an empty group
+ *
+ * 2) we don't want signal handlers that trigger in response to
+ * the action-removed signals that we're firing to attempt to
+ * modify the action group in a way that may cause it to fire
+ * additional signals (which we would then propagate)
+ */
+ g_object_unref (window->priv->actions);
+ window->priv->actions = NULL;
+
+ /* It's safe to send the signals now, if we need to. */
+ if (action_names)
+ {
+ for (i = 0; action_names[i]; i++)
+ g_action_group_action_removed (G_ACTION_GROUP (window), action_names[i]);
+
+ g_strfreev (action_names);
+ }
+ }
}
static void